package com.shanzmoo.core.manager.store;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.shanzmoo.base.bean.SResponse;
import com.shanzmoo.base.constant.*;
import com.shanzmoo.base.constant.e.StoreDeliveryBillTypeEnum;
import com.shanzmoo.base.constant.e.SysBillTypeEnum;
import com.shanzmoo.base.constant.e.SysOrderTypeEnum;
import com.shanzmoo.core.cache.CurrentUserCache;
import com.shanzmoo.core.domain.bo.ImportExcelDeliveryInfoBO;
import com.shanzmoo.core.domain.dto.StoreDeliveryBillDetailSaveDTO;
import com.shanzmoo.core.domain.dto.StoreDeliveryBillSaveDTO;
import com.shanzmoo.core.domain.dto.StoreDeliveryBillUpdateDTO;
import com.shanzmoo.core.manager.CodeManager;
import com.shanzmoo.db.store.entity.StoreDeliveryBillDetailEntity;
import com.shanzmoo.db.store.entity.StoreDeliveryBillEntity;
import com.shanzmoo.db.store.entity.StoreStockIoEntity;
import com.shanzmoo.db.store.entity.query.StoreDeliveryBillQuery;
import com.shanzmoo.db.store.entity.vo.StoreDeliveryBillDetailVO;
import com.shanzmoo.db.store.entity.vo.StoreDeliveryBillVO;
import com.shanzmoo.base.bean.PageRespBase;
import com.shanzmoo.db.store.service.IStoreDeliveryBillDetailService;
import com.shanzmoo.db.store.service.IStoreDeliveryBillService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 仓库发货单 管理器
 *
 * @author Gzhao 2021-03-03
 */
@Slf4j
@Component
public class StoreDeliveryBillManager {

    @Autowired
    private CodeManager codeManager;
    @Autowired
    private IStoreDeliveryBillService storeDeliveryBillService;
    @Autowired
    private IStoreDeliveryBillDetailService storeDeliveryBillDetailService;
    @Autowired
    private StoreStockManager storeStockManager;

    /**
     * 分页查询
     */
    public PageRespBase<StoreDeliveryBillVO> queryPage(StoreDeliveryBillQuery query) {
        Page page = PageHelper.startPage(query.getPageNum(), query.getPageSize());
        List<StoreDeliveryBillVO> reList = storeDeliveryBillService.queryPageList(query);

        // 获取发货单明细
        if (CollUtil.isNotEmpty(reList)) {
            List<Integer> ids = reList.stream().map(StoreDeliveryBillVO::getId).collect(Collectors.toList());
            List<StoreDeliveryBillDetailVO> detailAllList = storeDeliveryBillDetailService.queryListByIds(ids);

            for (StoreDeliveryBillVO storeDeliveryBillVO : reList) {
                List<StoreDeliveryBillDetailVO> detailList = detailAllList.stream()
                        .filter(e -> e.getBillId().equals(storeDeliveryBillVO.getId()))
                        .collect(Collectors.toList());
                storeDeliveryBillVO.setDetailList(detailList);
            }
        }

        PageRespBase<StoreDeliveryBillVO> result = PageRespBase.create(page, reList);
        PageHelper.clearPage();
        return result;
    }

    /**
     * 创建发货单
     */
    public Boolean createBill(String orderNo, StoreDeliveryBillTypeEnum typeEnum, Integer memberId, Integer outletId) {
        StoreDeliveryBillEntity storeDeliveryBillEntity = new StoreDeliveryBillEntity();
        storeDeliveryBillEntity.setMemberId(memberId);
        storeDeliveryBillEntity.setBillNo(codeManager.generateBillNo(SysBillTypeEnum.DELIVERY_BILL));
        storeDeliveryBillEntity.setOriginOrder(orderNo);
        storeDeliveryBillEntity.setOriginOrderType(typeEnum.getCode());
        storeDeliveryBillEntity.setOutletId(outletId);
        storeDeliveryBillEntity.setStatus(StoreDeliveryBillStatus.WAIT_SEND);
        storeDeliveryBillEntity.setCreateUser(CurrentUserCache.getUserId());

        storeDeliveryBillService.save(storeDeliveryBillEntity);
        return Boolean.TRUE;
    }

    /**
     * 取消发货单
     *
     * @param billId       发货单id
     * @param cancelReason 发货单取消原因
     * @return
     * @author Gzhao 2021/3/11
     */
    @Transactional(rollbackFor = Exception.class)
    public SResponse<Boolean> cancel(Integer billId, String cancelReason) {
        StoreDeliveryBillEntity bill = storeDeliveryBillService.getById(billId);
        if (bill == null || bill.getStatus() != StoreDeliveryBillStatus.WAIT_CONFIRM) {
            return SResponse.fail(ErrorCode.SYS_PARAM_ERROR);
        }
        bill.setStatus(StoreDeliveryBillStatus.CANCEL);
        bill.setCancelReason(cancelReason);

        storeDeliveryBillService.updateById(bill);

        return SResponse.ok(Boolean.TRUE);
    }

    /**
     * 更新发货单
     *
     * @param
     * @return
     * @author Gzhao 2021/3/11
     */
    @Transactional(rollbackFor = Exception.class)
    public SResponse<Boolean> update(StoreDeliveryBillUpdateDTO updateDto, Integer currentUserId) {
        StoreDeliveryBillEntity billEntity = updateDto.convertEntity();
        billEntity.setBillNo(codeManager.generateBillNo(SysBillTypeEnum.DELIVERY_BILL));
        billEntity.setStatus(StoreDeliveryBillStatus.WAIT_CONFIRM);
        billEntity.setUpdateUser(currentUserId);

        List<StoreDeliveryBillDetailEntity> detailEntityList = updateDto.getDetailList()
                .stream()
                .map(StoreDeliveryBillDetailSaveDTO::convertEntity)
                .collect(Collectors.toList());
        storeDeliveryBillService.updateBill(billEntity, detailEntityList);
        return SResponse.ok(Boolean.TRUE);
    }

    /**
     * 添加手动出库单
     *
     * @param
     * @return
     * @author Gzhao 2021/3/11
     */
    @Transactional(rollbackFor = Exception.class)
    public SResponse<Boolean> manualOut(StoreDeliveryBillSaveDTO saveDto, Integer currentUserId) {
        StoreDeliveryBillEntity billEntity = saveDto.convertEntity();
        billEntity.setBillNo(codeManager.generateBillNo(SysBillTypeEnum.DELIVERY_BILL));
        billEntity.setOriginOrderType(SysOrderTypeEnum.MANUAL_OUT_ORDER.getCode());
        billEntity.setStatus(StoreDeliveryBillStatus.WAIT_CONFIRM);
        billEntity.setMemberType(DeliberyBillMemberType.STORE_MEMBER_INFO);
        billEntity.setCreateUser(currentUserId);

        List<StoreDeliveryBillDetailEntity> detailEntityList = saveDto.getDetailList()
                .stream()
                .map(StoreDeliveryBillDetailSaveDTO::convertEntity)
                .collect(Collectors.toList());
        storeDeliveryBillService.saveBill(billEntity, detailEntityList);
        return SResponse.ok(Boolean.TRUE);
    }

    /**
     * 确认发货单状态
     *
     * @author Gzhao 2021/3/12
     * @param billId 发货单 id
     * @param userId
     * @return
     */
    public SResponse<Boolean> confirm(Integer billId, Integer userId) {
        StoreDeliveryBillEntity bill = storeDeliveryBillService.getById(billId);
        if (bill == null || bill.getStatus() != StoreDeliveryBillStatus.WAIT_CONFIRM) {
            return SResponse.fail(ErrorCode.SYS_PARAM_ERROR);
        }
        bill.setStatus(StoreDeliveryBillStatus.WAIT_SEND);
        bill.setUpdateUser(userId);

        storeDeliveryBillService.updateById(bill);
        return SResponse.ok(Boolean.TRUE);
    }

    /**
     * 发货
     *
     * @author Gzhao 2021/3/12
     * @param
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public SResponse<Boolean> send(StoreDeliveryBillEntity billEntity, Integer currentUserId) {
        /*
            1. 修改出库单状态
            2. 更新库存信息
         */
        StoreDeliveryBillEntity oldEntity = storeDeliveryBillService.getById(billEntity.getId());
        Assert.isTrue(oldEntity != null && oldEntity.getStatus() == StoreDeliveryBillStatus.WAIT_SEND,
                "只允许选择【待发货】订单发货");

        billEntity.setStatus(StoreDeliveryBillStatus.ALREADY_SEND);
        billEntity.setSendTime(LocalDateTime.now());
        billEntity.setSendUser(currentUserId);
        storeDeliveryBillService.updateById(billEntity);

        List<StoreDeliveryBillDetailEntity> billDetailList = storeDeliveryBillDetailService.lambdaQuery()
                .eq(StoreDeliveryBillDetailEntity::getDeleted, false)
                .eq(StoreDeliveryBillDetailEntity::getBillId, billEntity.getId())
                .list();

        List<StoreStockIoEntity> stockIoList = new ArrayList<>();
        for (StoreDeliveryBillDetailEntity detailEntity : billDetailList) {
            StoreStockIoEntity ssi = new StoreStockIoEntity();

            ssi.setSku(detailEntity.getSku());
            ssi.setType(StoreStockIoType.ORDER_OUT);
            ssi.setStoreCode(detailEntity.getStoreCode());
            ssi.setFlow(false);
            ssi.setSkuNum(detailEntity.getSkuNum());
            ssi.setOriginBill(oldEntity.getBillNo());
            ssi.setOriginBillType(3);
            ssi.setCreateUser(CurrentUserCache.getUserId());

            stockIoList.add(ssi);
        }
        // 更新实时库存
        storeStockManager.updateByIoList(stockIoList, CurrentUserCache.getUserId());

        return SResponse.ok(Boolean.TRUE);
    }

    /**
     * 导入签出：根据导入的 excel 文件生成发货单信息
     *
     * @param file excel 文件
     * @return
     * @author Gzhao 2021/3/12
     */
    @Transactional(rollbackFor = Exception.class)
    public SResponse<Boolean> importByExcel(MultipartFile file, Integer currentUserId) {
        List<ImportExcelDeliveryInfoBO> excelDataList = null;

        try {
            ExcelReader reader = ExcelUtil.getReader(file.getInputStream());
            excelDataList = reader.readAll(ImportExcelDeliveryInfoBO.class);
        } catch (IOException e) {
            log.error("上传文件获取失败", e);
            return SResponse.fail(Constant.ERRCODE_LOGIC, "Excel文件获取失败");
        }

        if (CollUtil.isEmpty(excelDataList)) {
            return SResponse.fail(Constant.ERRCODE_LOGIC, "Excel文件中未获取到发货信息");
        }
        // 过滤空行
        excelDataList = excelDataList.stream()
                .filter(e -> StrUtil.isNotEmpty(e.getConsigneeMobile()))
                .collect(Collectors.toList());

        // 校验 excel 数据
        checkData(excelDataList);

        List<String> mobileList = excelDataList.stream()
                .map(ImportExcelDeliveryInfoBO::getConsigneeMobile)
                .distinct()
                .collect(Collectors.toList());

        for (String mobile : mobileList) {
            List<ImportExcelDeliveryInfoBO> excelRowList = excelDataList.stream()
                    .filter(e -> e.getConsigneeMobile().equals(mobile))
                    .collect(Collectors.toList());

            ImportExcelDeliveryInfoBO excelRow = excelRowList.get(0);

            StoreDeliveryBillEntity billEntity = new StoreDeliveryBillEntity();

            billEntity.setBillNo(codeManager.generateBillNo(SysBillTypeEnum.DELIVERY_BILL));
            billEntity.setSendType(DeliverySendType.logistics);
            billEntity.setLogisticsNo(excelRow.getLogisticsNo());
            billEntity.setLogisticsCompany(excelRow.getLogisticsCompany());
            billEntity.setMemberId(currentUserId);
            billEntity.setMemberType(DeliberyBillMemberType.STORE_MEMBER_INFO);
            billEntity.setOriginOrderType(SysOrderTypeEnum.MANUAL_OUT_ORDER.getCode());
            billEntity.setStatus(StoreDeliveryBillStatus.WAIT_CONFIRM);
            billEntity.setConsignee(excelRow.getConsignee());
            billEntity.setConsigneeMobile(excelRow.getConsigneeMobile());
            billEntity.setConsigneeDistrict(excelRow.getConsigneeDistrict());
            billEntity.setConsigneeAddress(excelRow.getConsigneeAddress());
            billEntity.setRemark("excel 导入签出");
            billEntity.setCreateUser(currentUserId);

            // 组装发货商品明细数据
            List<StoreDeliveryBillDetailEntity> detailEntityList = new ArrayList<>();

            for (ImportExcelDeliveryInfoBO skuInfo : excelRowList) {
                StoreDeliveryBillDetailEntity detailEntity = new StoreDeliveryBillDetailEntity();

                detailEntity.setSku(skuInfo.getSku());
                detailEntity.setSkuNum(skuInfo.getSkuNum());
                detailEntity.setStoreCode(skuInfo.getStoreCode());

                detailEntityList.add(detailEntity);
            }
            storeDeliveryBillService.saveBill(billEntity, detailEntityList);
        }
        return SResponse.ok(Boolean.TRUE);
    }

    /**
     * 校验 excel 导入数据
     *
     * @param excelDataList excel 导入签出数据
     * @return
     * @author Gzhao 2021/3/12
     */
    private void checkData(List<ImportExcelDeliveryInfoBO> excelDataList) {
        /*
            todo
            1. 校验库位是否录入正确
            2. 校验商品sku是否录入正确
         */
    }

}
